1. ブラウザを知る──Webサイトを表示するアプリケーション
ブラウザ のコアとなる 3 つの役割
1. インターネット を通じて サーバ と通信する クライアント
2. HTML と CSS を描画する レンダリングエンジン
3. JavaScript を実行する JavaScript エンジン
インターネットを通じてサーバと通信するクライアント
クライアント / サーバモデル
インターネット と Web
HTTP
通信プロトコル
URL
DNS
CDN
HTML と CSS を描画する レンダリングエンジン
HTML
HTML のソースコードは、いくつかの手順を踏んでデータ構造を変化させながらブラウザによって解析される
code:mermaid
flowchart LR
文字列 --> トークン
トークン --> DOMツリー
トークン(HTML トークン)
HTML を細かく区切ったときに意味のある文字列の最小単位
6 つの種類がある(https://arc.net/l/quote/gnxapsqh)
1. DOCTYPE: 文書がどのバージョンの HTML を使用するのかを表す
<!DOCTYPE html>
2. 開始タグ: 終了タグとともに使用され、ある要素の開始を表す
e.g. <p>
3. 終了タグ: 開始タグとともに使用され、ある要素の終了を表す
e.g. </p>
4. コメント: 文書の結果に影響はしないコメントを表す
5. 文字: タグを含まない純粋な文字
6. EOF: ファイルの終了を表す
DOM ツリー
DOM: HTML 文書の構造とコンテンツを表すデータ構造
これにより、JavaScript などのスクリプト言語から HTML を操作・利用することが可能
DOM ツリーは、ノードによって構成される
ノードは Node インタフェース を実装するオブジェクト
インタフェースは DOM Living Standard の仕様書で IDL によって記述される
code:_
Exposed=Window
interface Node : EventTarget {
const unsigned short ELEMENT_NODE = 1;
...
readonly attribute Node? firstChild;
readonly attribute Node? lastChild;
readonly attribute Node? previousSibling;
readonly attribute Node? nextSibling;
...
CEReactions Node appendChild(Node node);
CEReactions Node replaceChild(Node node, Node child);
CEReactions Node removeChild(Node child);
};
インタフェースを実装したオブジェクトは、インタフェースで定義されているデータへのアクセスや操作が可能
e.g.
firstChild フィールドが存在するので、DOM ツリーのすべてのノードは firstChild メンバを持つ
appendChild という操作によって、現在のノード配下に新しいノード(子ノード)を追加できる
インタフェースは 継承 できる
Node インタフェースを継承しているインタフェースは 2024 年現在以下の 9 つ
Element インタフェース
それぞれのタグに対応したインタフェースが、この Element インタフェースを継承する形で実装される
e.g. <a>
code:mermaid
flowchart LR
HTMLAnchorElement --> HTMLElement --> Element --> Node
Attr インタフェース
Text インタフェース
CDATASection インタフェース
ProcessingInstruction インタフェース
Comment インタフェース
Document インタフェース
DocumentType インタフェース
DocumentFragment インタフェース
CSS
CSS もいくつかの手順を踏んでデータ構造を変化させながらブラウザによって解析される
code:mermaid
flowchart LR
文字列 --> トークン --> CSSOM
トークン(CSS トークン)
CSS を細かく区切ったときに意味のある文字列の最小単位
トークンは CSS Syntax Module Level 3 で 24 種類定義されているが、ここでは 8 種類のみを抜粋
ident-token: 変数などの識別子を表す
number-token: 数字を表す
hash-token: ハッシュ記号を表す
delim-token: 区切り文字を表す
colon-token: コロンを表す
semicolon-token: セミコロンを表す
{-token: 始め波括弧を表す
}-token: 終わり波括弧を表す
CSSOM
ブラウザが CSS の種類を解析し、ツリーの形で表現したデータ構造
CSSOM の情報に基づいてツリーの各ノードにスタイルを適用したり、各ノードの大きさや位置を決定する
DOM ツリー同様、ノードによって構成される
違いとしては、DOM ツリーはすべてのノードが Node インタフェースを実装しているが、CSSOM には様々な種類のノードが存在 する
e.g.
CSSStyleSheet インタフェース
1 つの CSS 文書のルートノードを表す
IDL による定義
code:_
Exposed=Window
interface CSSStyleSheet : StyleSheet {
constructor(optional CSSStyleSheetInit options = {});
readonly attribute CSSRule? ownerRule;
SameObject readonly attribute CSSRuleList cssRules;
unsigned long
insertRule(CSSOMString rule, optional unsigned long index = 0);
undefined deleteRule(unsigned long index);
Promise<CSSStyleSheet> replace(USVString text);
undefined replaceSync(USVString text);
};
CSSRuleList cssRules : どのセレクタに対してどのようなスタイルを適用するかを表す CSS ルールのリスト
CSSStyleRule インタフェース
1 つの CSS ルールのノードを表す
IDL による定義
code:_
Exposed=Window
interface CSSStyleRule : CSSGroupingRule {
attribute CSSOMString selectorText;
SameObject, PutForwards=cssText
readonly attribute CSSStyleProperties style;
};
CSSOMString selectorText: セレクタ
CSSStyleProperties style: プロパティに対する値
e.g.
CSS
code:css
.class {
background-color: red;
}
p {
color: blue;
}
CSSOM
https://scrapbox.io/files/673342b05c802ecbef1df1af.png
レイアウトツリー / レンダーツリー
ブラウザ が Web ページを表示するために、HTML と CSS をもとに作成する内部的なデータ構造
名称はブラウザによって異なる
DOM ツリーと CSSOM の情報を元に作成され、以下を決定する
各要素が画面上のどこに配置されるか
各要素の幅や高さ
どの要素が他の要素の子要素・兄弟要素であるか
...
e.g.
HTML + CSS
code:html
<html>
<style>
h1 {
color: red;
}
.foo {
display: none;
}
</style>
<body>
<h1>Hello World</h1>
<p class="foo">This is sample text.</p>
</body>
</html>
レイアウトツリー
https://scrapbox.io/files/673344583c26c0ab21be522d.png
JavaScript を実行する JavaScript エンジン
JavaScript エンジン = JavaScript の解釈と実行を行うソフトウェア
2024 年現在の JavaScript の仕様書は ECMAScript 2024 Language Specification
e.g. 変数定義(VariableStatement)
VariableStatement : var VariableDeclarationList ;
JavaScript も HTML や CSS 同様、文字列をトークンに分割し、抽象構文木(AST)と呼ばれる 木構造 を作成することで解釈する
code:mermaid
flowchart LR
文字列 --> トークン --> AST
トークン(JavaScript トークン)
JavaScript を細かく区切ったときに意味のある文字列の最小単位
ECMAScript 2024 Language Specification で定義しているトークンの一部
IdentificationName: 変数などの識別子を表す
ReservedWord: await や var、const などの 予約語 を表す
Punctuator: 記号を表す
NumericLiteral: 数字を表す
StringLiteral: 文字列を表す
AST
ノードによって構成されており、CSSOM のように様々な種類のノードが存在する
e.g.
AdditiveExpression: 足し算または引き算のノード
BNF で以下のように定義される
code:_
AdditiveExpression :
MultiplicativeExpression
AdditiveExpression + MultiplicativeExpression
AdditiveExpression - MultiplicativeExpression
VariableDeclaration: 変数宣言のノード
code:_
VariableDeclaration :
BindingIdentifier Initializer
BuildingPattern Initializer
BindingIdentifier: 変数の名前を表す
BuildingPattern: const [a, b] = [1, 2]; のようなパターンによる複数の変数を表す
Initializer: 初期化式
ブラウザ API
DOM API や Fetch API などブラウザが提供する API の総称
DOM API
DOM を操作する API
JavaScript 言語の仕様とは無関係であり、独立して存在する
e.g. JavaScript で特定のタグのノードを取得する
code:js
const nodes = document.getElementByTagName('h1');
上記は W3C が管理する DOM Living Standard の Document インタフェースで定義されている
code:_
Exposed=Window
interface Document : Node {
...
HTMLCollection getElementsByTagName(DOMString qualifiedName);
...
};
コアの役割を支えるためのさらなる機能
現在のブラウザでは、上記の 3 つのコアの役割に加え、ユーザが使いやすくなるような機能が多く含まれている
e.g.
ストレージ
Cookie
Local Storage
Session Storage
キャッシュ
ブラウザは、HTML や CSS、JavaScript、画像、動画などのリソースをキャッシュする
リソースが再度リクエストされた際に、キャッシュに保存されている場合はブラウザから提供され、ネットワーク 経由の ダウンロード が省略される
これにより、Web サイトの読み込み速度の向上が期待できる
キャッシュは HTTP ヘッダ(Cache-Control や Expires、Last-Modified など)によって制御可能
保存されたデータは有効期限を過ぎると削除される
拡張機能
誰でも開発でき、機能を公開することで様々な人にブラウザに追加の機能やカスタマイズを提供できる機能
e.g.
Google Chrome: Chrome Web Store
Firefox: Firefox Add-ons
parcel
UI に関する機能
タブのグループ化・ピン留め
ブックマーク
履歴
プッシュ通知
音声検索・操作
シークレットモード
パスワード管理
...
マルチプロセスアーキテクチャ
上記の役割や機能は、現代のブラウザでは複数の プロセス 上で動いていることが多い
このようなブラウザの設計方法をマルチプロセスアーキテクチャと呼ぶ
プロセス
仕様などで決まっているわけではないが、ブラウザでは主に 2 種類のプロセスが存在する
ブラウザプロセス: データの保管やネットワークの通信など、Web ブラウザ の重要な機能を扱うための プロセス
レンダラプロセス: HTML や CSS、JavaScript を解釈し、レンダリング するための プロセス
ブラウザを開くと、まずブラウザプロセスが起動する
そしてタブを 1 つ開くと、1 つのレンダラプロセスが起動する
つまり、10 個タブを開くと 1 個のブラウザプロセスと約 10 個のレンダラプロセスが存在する
warning.icon <iframe> コンテンツも別のレンダラプロセスで実行できるなど、必ずしもタブとレンダラプロセスは 1 : 1 ではない
なぜこれらのプロセスが分離されているか?
HTML や CSS、JavaScript などのリソースは誰が書いたか分からないため信用できない
そこでプロセスを分離すると、メモリ空間も分離され、重要な情報を扱うブラウザプロセスへのアクセスを防げる
スレッド
仕様などで決まっているわけではないが、ブラウザでは UI スレッド(メインスレッド) と複数の バックグラウンドスレッド 上でプログラムが実行されることが多い
UI スレッド(メインスレッド): ユーザとの インタラクション を扱ったり、画面の描画を行ったりするコアとなるスレッド
バックグラウンドスレッド: ネットワークの処理などを行う
その他、ユーザが制御できる ワーカースレッド というものも存在する
warning.icon iOS 上でのブラウザアプリ
シングルプロセス のブラウザ
「ブラウザはマルチプロセスで動いている」と上述したが、iOS で動くブラウザアプリは例外
Apple の規約により、アプリストアに掲載する iOS アプリは シングルプロセス で動かさなければならない
radish-miyazaki.icon
AppReview ガイドライン を見たが、具体的なソースは見つからなかった
経験則 ??
が、Stack overflow に以下のような質問があった
https://stackoverflow.com/questions/78999016/does-ios-support-multi-process-apps-like-android-does
また、レンダリングエンジンも Apple が開発している WebKit を使用する必要がある
具体的には WKWebView という API を使用して、HTML や CSS の描画をする必要がある
ただし、EU における DMA の施行により、Apple によって iOS で設けられていた制限が緩和された
https://developer.apple.com/support/alternative-browser-engines/
https://github.com/mozilla/platform-tilt/issues/2
しかし、日本は適用外であるため、日本で使用される iOS のブラウザアプリは引き続き WKWebView を使う必要がある
ブラウザのセキュリティ対策
サイト分離
同一生成元ポリシー
コンテンツセキュリティポリシー(CSP)
#読書メモ